AWS CDK v2のスナップショットテストでアセットを無視する方法
以前、AWS CDKのスナップショットテストで、ハッシュを置換しアセットを無視する方法を紹介しました。
この方法はAWS CDK v1のお話でして、v2では使えません。というわけで、このエントリではCDK v2でアセットを無視する方法を紹介します。
忙しい人のための結論
test/snapshot-plugin.ts
を次のように修正すればCDK v2で動作します(Snapshot Serializerを利用している場合)。
module.exports = { test: (val: unknown) => typeof val === 'string', serialize: (val: string) => { return `"${val.replace(/([A-Fa-f0-9]{64}.zip)/, 'HASH-REPLACED.zip')}"`; }, };
普通にスナップショットテストをしてみる
v1のエントリをv2でなぞり直します。
まずはスナップショットの差分が発生することを確認しましょう。プロジェクトを作成していきます。
$ mkdir cdk-ignore-test-assets && cd $_ $ npx cdk@2 init --language typescript $ npm install @aws-cdk/aws-lambda-python-alpha
次にLambda関数のファイルを作成します。
def handler(event, context): return "success"
スタックファイルを更新します。
import { Stack, StackProps } from "aws-cdk-lib"; import { Construct } from "constructs"; import { PythonFunction } from "@aws-cdk/aws-lambda-python-alpha"; import { Runtime } from "aws-cdk-lib/aws-lambda"; export class CdkIgnoreTestAssetsStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); new PythonFunction(this, "LambdaFunction", { entry: "lib/lambda/hello", runtime: Runtime.PYTHON_3_9, }); } }
テストファイルも更新します。
import { App } from "aws-cdk-lib"; import { Template } from "aws-cdk-lib/assertions"; import { CdkIgnoreTestAssetsStack } from "../lib/cdk-ignore-test-assets-stack"; test("Snapshot Test", () => { const app = new App(); const stack = new CdkIgnoreTestAssetsStack(app, "cdkIgnoreTestAssetsStack"); expect(Template.fromStack(stack).toJSON()).toMatchSnapshot(); });
この状態で一度テストを実行します。
$ npm run test
取得したスナップショットを抜粋します。次のような内容が確認できます。
// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Snapshot Test 1`] = ` Object { "Parameters": Object { "BootstrapVersion": Object { "Default": "/cdk-bootstrap/hnb659fds/version", "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]", "Type": "AWS::SSM::Parameter::Value<String>", }, }, "Resources": Object { "LambdaFunctionBF21E41F": Object { "DependsOn": Array [ "LambdaFunctionServiceRoleC555A460", ], "Properties": Object { "Code": Object { "S3Bucket": Object { "Fn::Sub": "cdk-hnb659fds-assets-\${AWS::AccountId}-\${AWS::Region}", }, "S3Key": "2b75c1affb2060ce201327fd694b7f436c08fdeb0e229fe637c9dd63d5c7798a.zip", }, "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ "LambdaFunctionServiceRoleC555A460", "Arn", ], }, "Runtime": "python3.9", }, "Type": "AWS::Lambda::Function", },
S3Key
の部分にアセット名が入っています。Lambdaのコードを修正することで、テストが失敗することも確認してみましょう。
diff --git a/lib/lambda/hello/index.py b/lib/lambda/hello/index.py index a2c6b78..f87f532 100644 --- a/lib/lambda/hello/index.py +++ b/lib/lambda/hello/index.py @@ -1,2 +1,2 @@ def handler(event, context): - return "success" + return "success!!"
テストを実行します。
$ npm run test > [email protected] test > jest RUNS test/cdk-ignore-test-assets.test.ts FAIL test/cdk-ignore-test-assets.test.ts (16.294 s) ✕ Snapshot Test (5479 ms) ● Snapshot Test expect(received).toMatchSnapshot() Snapshot name: `Snapshot Test 1` - Snapshot - 1 + Received + 1 @@ -14,11 +14,11 @@ "Properties": Object { "Code": Object { "S3Bucket": Object { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", }, - "S3Key": "2b75c1affb2060ce201327fd694b7f436c08fdeb0e229fe637c9dd63d5c7798a.zip", + "S3Key": "50a81b2cd570ab34a55020d7f74bc683b717c74b973f810fd59b4707ecb61f1f.zip", }, "Handler": "index.handler", "Role": Object { "Fn::GetAtt": Array [ "LambdaFunctionServiceRoleC555A460", 7 | const stack = new CdkIgnoreTestAssetsStack(app, "cdkIgnoreTestAssetsStack"); 8 | > 9 | expect(Template.fromStack(stack).toJSON()).toMatchSnapshot(); | ^ 10 | }); 11 | at Object.<anonymous> (test/cdk-ignore-test-assets.test.ts:9:46) › 1 snapshot failed. Snapshot Summary › 1 snapshot failed from 1 test suite. Inspect your code changes or run `npm test -- -u` to update them. Test Suites: 1 failed, 1 total Tests: 1 failed, 1 total Snapshots: 1 failed, 1 total Time: 16.47 s, estimated 137 s Ran all test suites.
失敗しましたね。
アセットを無視するスナップショットテストをやってみる
それではアセットで差分が出ることは確認できましたので、このエントリの目的である、それを無視するスナップショットテストをやってみましょう。
まずはモジュールを定義します。
module.exports = { test: (val: unknown) => typeof val === 'string', serialize: (val: string) => { return `"${val.replace(/([A-Fa-f0-9]{64}.zip)/, 'HASH-REPLACED.zip')}"`; }, };
このモジュールを使用するように、設定ファイルを編集します。
module.exports = { roots: ['<rootDir>/test'], testMatch: ['**/*.test.ts'], transform: { '^.+\\.tsx?$': 'ts-jest' }, snapshotSerializers: ['<rootDir>/test/snapshot-plugin.ts'] };
一度スナップショットは削除して、テストを実行してみます。
$ rm test/__snapshots__/cdk-ignore-test-assets.test.ts.snap $ npm run test
スナップショットを確認してみると、HASH-REPLACED.zip
に置き換わっていることが確認できます。
"Properties": Object { "Code": Object { "S3Bucket": Object { "Fn::Sub": "cdk-hnb659fds-assets-\${AWS::AccountId}-\${AWS::Region}", }, "S3Key": "HASH-REPLACED.zip",
この状態で、先ほどと同じようにLambda関数のコードを書き換えて、再度テストしてみましょう。
$ npm run test > [email protected] test > jest RUNS test/cdk-ignore-test-assets.test.ts PASS test/cdk-ignore-test-assets.test.ts (12.168 s) ✓ Snapshot Test (2237 ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 1 passed, 1 total Time: 12.389 s, estimated 15 s Ran all test suites.
アセットが変わってもテストをパスしました!
まとめ
CDK v1とv2では出力されるデータに差異があるため、置換する処理も合わせて変更する必要がありました。CDK v2でもスナップショットテストを導入しようとしている方の参考になれば幸いです。